package cn.ibizlab.util.domain;

import cn.ibizlab.util.helper.JacksonUtils;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.ibatis.session.SqlSession;
import org.springframework.data.annotation.Transient;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

@Data
@Accessors(chain = true)
@TableName("logging_event")
@ApiModel(description = "日志事件")
public class LoggingEvent extends Model<LoggingEvent> implements Serializable {

    @ApiModelProperty(value = "事件ID", example = "1")
    @TableId(value = "event_id", type = IdType.ASSIGN_ID)
    private Long eventId;

    @ApiModelProperty(value = "时间戳", example = "1621339441000")
    @TableField("timestmp")
    private Long timeStamp;

    @ApiModelProperty(value = "日志消息", example = "这是一条测试日志")
    @TableField("formatted_message")
    private String formattedMessage;

    @ApiModelProperty(value = "日志记录器名称", example = "com.example.LoggingDemo")
    @TableField("logger_name")
    private String loggerName;

    @ApiModelProperty(value = "日志级别", example = "INFO")
    @TableField("level_string")
    private String levelString;

    @ApiModelProperty(value = "线程名称", example = "main")
    @TableField("thread_name")
    private String threadName;

    @ApiModelProperty(value = "参考标志", example = "1")
    @TableField("reference_flag")
    private Integer referenceFlag;

    @ApiModelProperty(value = "参数0", example = "param0")
    @TableField("arg0")
    private String arg0;

    @ApiModelProperty(value = "参数1", example = "param1")
    @TableField("arg1")
    private String arg1;

    @ApiModelProperty(value = "参数2", example = "param2")
    @TableField("arg2")
    private String arg2;

    @ApiModelProperty(value = "参数3", example = "param3")
    @TableField("arg3")
    private String arg3;

    @ApiModelProperty(value = "调用者文件名", example = "LoggingDemo.java")
    @TableField("caller_filename")
    private String callerFilename;

    @ApiModelProperty(value = "调用者类名", example = "com.example.LoggingDemo")
    @TableField("caller_class")
    private String callerClass;

    @ApiModelProperty(value = "调用者方法名", example = "main")
    @TableField("caller_method")
    private String callerMethod;

    @ApiModelProperty(value = "MDC 属性映射", example = "{\"userId\":123}")
    @TableField(exist = false)
    private LinkedHashMap<String,Object> mdcPropertyMap;

    @Transient
    public Collection<LoggingEventProperty> getMdcProperties() {
        if(!ObjectUtils.isEmpty(mdcPropertyMap)) {
            return mdcPropertyMap.entrySet().stream().filter(e->e.getValue()!=null)
                    .map(entry -> new LoggingEventProperty().setEventId(this.getEventId()).setMappedKey(entry.getKey()).setMappedValue(JacksonUtils.toJson(entry.getValue())))
                    .collect(Collectors.toList());
        }
        return null;
    }

    public LoggingEvent set(String key,Object value) {
        if(!ObjectUtils.isEmpty(value)) {
            if(mdcPropertyMap == null)
                mdcPropertyMap = new LinkedHashMap<>();
            mdcPropertyMap.put(key,value);
        }
        return this;
    }

    public Object get(String key) {
        if(mdcPropertyMap == null)
            return null;
        return mdcPropertyMap.get(key);
    }

    public boolean save() {
        SqlSession sqlSession = sqlSession();
        try {
            boolean result = SqlHelper.retBool(sqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE), this));
            if (result) {
                Collection<LoggingEventProperty> mdcProperties = getMdcProperties();
                if (!ObjectUtils.isEmpty(mdcProperties)) {
                    String propSQL = SqlHelper.table(LoggingEventProperty.class).getSqlStatement(SqlMethod.INSERT_ONE.getMethod());
                    for (LoggingEventProperty property : mdcProperties) {
                        result = SqlHelper.retBool(sqlSession.insert(propSQL, property));
                        if (!result)
                            break;
                    }
                }
            }
            return result;
        } finally {
            closeSqlSession(sqlSession);
        }
    }

    public static boolean saveBatch(List<LoggingEvent> list) {
        if(!ObjectUtils.isEmpty(list)) {
            SqlSession sqlSession = list.get(0).sqlSession();
            try {
                String eventSQL = SqlHelper.table(LoggingEvent.class).getSqlStatement(SqlMethod.INSERT_ONE.getMethod());
                String propSQL = SqlHelper.table(LoggingEventProperty.class).getSqlStatement(SqlMethod.INSERT_ONE.getMethod());

                for(LoggingEvent event:list) {
                    boolean result = SqlHelper.retBool(sqlSession.insert(eventSQL, event));
                    if (result) {
                        Collection<LoggingEventProperty> mdcProperties = event.getMdcProperties();
                        if (!ObjectUtils.isEmpty(mdcProperties))
                            mdcProperties.forEach(property->sqlSession.insert(propSQL, property));
                    }
                }
            } catch (Exception ex) {

            }
            finally {
                list.get(0).closeSqlSession(sqlSession);
            }
        }
        return true;
    }

}